import { AstTreeUtils } from "arkanalyzer";
import { ts, NodePredicate } from "qvog-dsl";
import { native, ObjectLiteralExpression, rule, HomeCheckHint } from "qvog-dsl";

const SEVERITY = 1;
const DOC_PATH = '';
const DESCRIPTION = 'Unexpected whitespace between function name and paren.';

type RangNum = [charCount: number, newlineCount: number];
type Options = [
  'always' | 'never',
  {
    allowNewlines?: boolean;
  }?
];
const defaultOptions: Options = ['never', {allowNewlines: false}]; //默认never

export const Statement: NodePredicate<ts.Statement> = {
  is(node: ts.Node): node is ts.Statement {
    return ts.isCallExpression(node) || ts.isNewExpression(node);
  },
};

export default native<HomeCheckHint>()()
  .match(Statement)
  .when((node: ts.Statement): boolean => {
    const chdLength = node.getChildren().length;
    if (chdLength === 4 || chdLength === 5) {
      const { nameConcent, openParenToken, syntaxList, closeParenToken } = extractCallExpressionParts(node);
      if (nameConcent) {
        const methodName = nameConcent.getText();
        const nodeText = node.getText();
        const rangeNum = countCharactersAndNewlines(node.getSourceFile(), node, nameConcent, openParenToken); //获取空格数和换行符数
        const startPosition = ts.getLineAndCharacterOfPosition(
          node.getSourceFile(),
          nameConcent.getEnd()
        ); //获取位置信息
        const rangeStart = node.getStart();
        const rangeEnd = node.getEnd();
        return exceFix(
          nodeText,
          rangeStart,
          rangeEnd,
          defaultOptions,
          rangeNum,
          startPosition,
          methodName
        );
      }
    }
    return false;
  })
  .report({
    severity: SEVERITY,
    description: DESCRIPTION,
    docPath: DOC_PATH,
  });


function extractCallExpressionParts(child: ts.Node): {
  nameConcent: ts.Node;
  openParenToken: ts.Node;
  syntaxList: ts.Node;
  closeParenToken: ts.Node
} {
  const children = child.getChildren();
  let newKeyWord: ts.Node;
  let nameConcent: ts.Node;
  let openParenToken: ts.Node;
  let syntaxList: ts.Node;
  let closeParenToken: ts.Node;
  const callExpr = ts.isCallExpression(child);
  const cdLength = children.length;
  if (callExpr) {
    // 情况 1: 没有 new 关键
    nameConcent = children[0];
    openParenToken = children[cdLength - 3];
    syntaxList = children[cdLength - 2];
    closeParenToken = children[cdLength - 1];
  } else {
    // 情况 2: 有 new 关键字
    newKeyWord = children[0];
    nameConcent = children[1];
    openParenToken = children[cdLength - 3];
    syntaxList = children[cdLength - 2];
    closeParenToken = children[cdLength - 1];
  }
  return { nameConcent, openParenToken, syntaxList, closeParenToken };
}

function countCharactersAndNewlines(sourceFile: ts.SourceFile, child: ts.Node, nameConcent: ts.Node, openParenToken: ts.Node): RangNum {
  // 确保范围有效
  const startIndex = sourceFile.getLineAndCharacterOfPosition(nameConcent.getEnd()); // 获取 nameConcent 的结束位置
  const endIndex = sourceFile.getLineAndCharacterOfPosition(openParenToken.getStart()); // 获取 openParenToken 的开始位置
  const newlineCount = endIndex.line - startIndex.line;
  const nameConcentText = nameConcent.getText();
  const fullText = child.getText();
  const startdex = fullText.lastIndexOf(nameConcentText) + nameConcentText.length;
  let charCount = 0;
  if (newlineCount > 0) {
    charCount = newlineCount + endIndex.character;
  } else {
    charCount = endIndex.character - startIndex.character;
  }
  // 统计字符数和换行符数
  const subString = fullText.substring(startdex, startdex + charCount).replace('?', '').replace('.', '');
  return [subString.length, newlineCount];
}


function exceFix(
    nodeText: string,
    rangeStart: number,
    rangeEnd: number,
    mergedOptions: Options,
    rangeNum: RangNum,
    startPosition: ts.LineAndCharacter,
    methodName: string
  ): boolean {
    if (
      mergedOptions.length > 0 &&
      mergedOptions[0] === 'never' &&
      rangeNum[0] > 0
    ) {
      return true;
      
    } else if (
      mergedOptions.length > 0 &&
      mergedOptions[0] === 'always' &&
      rangeNum[0] === 0
    ) {
      return true;
    } else if (
      mergedOptions.length > 0 &&
      !mergedOptions[1]?.allowNewlines &&
      mergedOptions[0] === 'always' &&
      rangeNum[1] > 0
    ) {
      return true;
    } 
    return false;
  }